﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using IsikFx.Project.Utils;

namespace IsikFx.Project.Core
{
    public class TypeInvoker : AbstractTypeInvoker
    {

        /// <summary>
        /// InvokeService
        /// </summary>
        /// <param name="_serviceProxy"></param>
        /// <param name="_operationName"></param>
        /// <param name="_parameters"></param>
        /// <returns></returns>
        public override object InvokeService(Type _serviceProxy, string _operationName, params object[] _parameters)
        {
            object response = null;
            try
            {
                MethodInfo method = _serviceProxy.GetMethod(_operationName, BindingFlags.Public | BindingFlags.Instance);
                object serviceProxy = Activator.CreateInstance(_serviceProxy);

                if (method != null)
                {
                    ParameterInfo[] parameters = method.GetParameters();
                    if (parameters != null && parameters.Length > 0)
                    {
                        if (_parameters != null && _parameters.Length > 0)
                        {
                            NormalizeParameters(_parameters);
                            response = method.Invoke(serviceProxy, _parameters);
                        }
                        else
                        {
                            throw new Exception("Parameters cannot be null");
                        }
                    }
                    else
                    {
                        response = method.Invoke(serviceProxy, null);
                    }
                }
            }
            catch (Exception ex)
            {
                ExceptionHelper.HandleException(ex, typeof(TypeInvoker));
            }

            return response;
        }

        /// <summary>
        /// Converts to List type parameters to array.
        /// </summary>
        /// <param name="_params"></param>
        private void NormalizeParameters(params object[] _params)
        {
            Type tip = typeof(object);
            for (int i = 0; i < _params.Length; i++)
            {
                if (_params[i] is IList)
                {
                    IList listParams = (_params[i] as IList);
                    IEnumerator enumerator = listParams.GetEnumerator();
                    enumerator.Reset();
                    if (enumerator.MoveNext())
                    {
                        object current = enumerator.Current;
                        tip = current.GetType();
                    }
                    Array arr = Array.CreateInstance(tip, listParams.Count);
                    (_params[i] as ICollection).CopyTo(arr, 0);
                    _params[i] = arr;
                }
            }
        }
    }
}
